<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>Hexas 2.0</title>
		<link rel="stylesheet" type="text/css" href="style.css" />
		<script type="text/javascript" src="jquery.js"></script>
		<script type="text/javascript" src="hexa.js"></script>
		<script type="text/javascript">
S.hexaGrama = {
	width: 1200,
	height: 600,
	ro: 50,
	svg: null,
	layers: null,
	selecteds: null,
	make: function () {
				
		this.layers = new Array();
		
		this.svg = S.svg("svg");
		
		this.svg.setAttribute("width", this.width + "px");
		this.svg.setAttribute("height", this.height + "px");
		
		this.selecteds = new Array();
		
		S.hexaGramas.push(this); 
		
		var myLayer = object(S.hexaLayer);
		myLayer.make();
		myLayer.draw(this);
		
		////////////////////// ATTACH EVENTS HERE ////////////
		this.svg.ondblclick = function (e) {
			
			if (e.target.tagName == "svg") {
				
				var hexaGrama = S(e.target);
				
				hexaGrama.addHexa(e.clientX, e.clientY);
				
			}
			
		}
		
		this.svg.onmouseup = function (e) {
			
			if (e.target.tagName == "path") {
				
				var layer;
				if (e.target.getAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type") == "auxHexa") {
				
					var auxHexa = S(e.target)
					
					layer = auxHexa.parent;
					
					// Here is supposed to tell this guy that well, you know. Another hexa blah blah
					try {
						layer.addHexa(auxHexa.x, auxHexa.y);
					} catch (err) {}
					
				} else if (e.target.getAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type") == "hexa" ||
						e.target.getAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type") == "signalHexa") {
					
					layer = S(e.target).parent;
					
				} else if (e.target.getAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type") == "opaqueLayer") {
				
					layer = S(e.target);
				
				}
				
				$(layer.auxLayer).empty();
				
			}
			
			
			
		}
		
	}, 
	draw: function (div) {
		
		if (!div) {
			throw new Error("Div expected");
			return;
		}
		this.div = div;
		div.appendChild(this.svg);
		
	},	
	onTop: function () {
		
		for (var j = (this.layers.length - 1); j >= 0; j --) {
		
			if (this.layers[j].visible) {
				return this.layers[j];
			}
			
		}
		
	},
	deselectAll: function () {
		
		for (var i = this.selecteds.length - 1; i >= 0; i --) {
			
			var toDeselect = this.selecteds.pop();
			toDeselect.deselect();
			
		}
		
	}
}

S.hexaLayer = {
	auxLayer: null,
	layer: null,
	parent: null,
	visible: true,
	show: function () {
		
		this.opaqueLayer.layer.style.display = "";
		this.auxLayer.style.display = "";
		this.layer.style.display = "";
		this.visible = true;
		
	}, 
	hide: function () {
	
		// When hiding a layer, we must check if there's something in it interesting
		// If there is something, the hexa must change its style to show it
		// Else, it must be a normal hexa.
		if (this.hexas.length > 1) { // Greater than one, because there's always one - the signalHexa
			this.hexa.addClass("holder-hexa");
			this.hexa.contains = true;
		} else {
			this.hexa.removeClass("holder-hexa");
			this.hexa.contains = false;
		}
		
		this.opaqueLayer.layer.style.display = "none";
		this.auxLayer.style.display = "none";
		this.layer.style.display = "none";
		this.visible = false;
		
	},
	make: function () {
	
		this.hexas = new Array();
		this.auxHexas = new Array();
		
		this.opaqueLayer = {
			layer: S.svg("g"),
			path: S.svg("path"),
			draw: function(parent) {
				
				if (!parent) {
					throw Error("Parent hexaGrama was expected");
					return;
				}
				
				this.layer.setAttribute("class", "opaque-layer");
				this.path.setAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type", "opaqueLayer");
				this.path.setAttribute("d", "M 0, 0 L " + parent.width + ", 0 L " + parent.width + ", " + parent.height + " L 0, " + parent.height + " L 0, 0");
				
				this.layer.appendChild(this.path);
				
				parent.svg.appendChild(this.layer);
				
			}
		}
		
		this.auxLayer = S.svg("g");
		this.layer = S.svg("g");
		
	},
	draw: function (hexaGrama, hexa) {
		
		this.parent = hexaGrama;
		if (hexa) { this.hexa = hexa; };
		this.auxLayer = S.svg("g");
		this.layer = S.svg("g");
		
		this.auxLayer.setAttribute("class", "auxiliary-layer");
		this.layer.setAttribute("class", "layer");
		
		for (auxHexa in this.auxHexas)
			auxHexa.draw(this);
			
		for (hexa in this.hexas)
			hexa.draw(this);
		
		
		this.opaqueLayer.draw(hexaGrama);

		hexaGrama.svg.appendChild(this.auxLayer);
		hexaGrama.svg.appendChild(this.layer);		
		
		hexaGrama.layers.push(this);
		
		///// Event handlers here ///////////
		this.opaqueLayer.path.ondblclick = function (e) {
		
			if (e.target.tagName == "path") {
		
				var l = S(e.target);
				
				l.addHexa(e.clientX, e.clientY);
				
			}
			
		}
		
	},
	addHexa: function(x, y) {
		
		if (this.isOccupied(x, y)) {
			throw new Error("Wrong place!");
			return false;
		}
		
		var myHexa = object(S.hexa);
		myHexa.make(x, y, this.parent.ro);
		
		myHexa.draw(this);
		
	},
	addAuxHexa: function(x, y) {
		
		var myAuxHexa = object(S.auxHexa);
		
		myAuxHexa.make(x, y, this.parent.ro);
		
		myAuxHexa.draw(this);
		
	}

}

S.baseHexa = {
	x: null,
	y: null,
	ro: null,
	path: null,
	position: function () {

		this.N = {
			x: this.x, 
			y: this.y - this.ro};
		this.NE = {
			x: this.x + this.ro * 0.866, 
			y: this.y - this.ro / 2};
		this.SE = {
			x: this.x + this.ro * 0.866, 
			y: this.y + this.ro / 2};
		this.S = {
			x: this.x, 
			y: this.y + this.ro};
		this.SW = {
			x: this.x - this.ro * 0.866, 
			y: this.y + this.ro / 2};
		this.NW = {
			x: this.x - this.ro * 0.866, 
			y: this.y - this.ro / 2};
		
		this.sNE = {
			x: this.x + this.ro * 0.866, 
			y: this.y - this.ro * 1.5};
		this.sE = {
			x: this.x + this.ro * 0.866 * 2, 
			y: this.y};
		this.sSE = {
			x: this.x + this.ro * 0.866, 
			y: this.y + this.ro * 1.5};
		this.sSW = {
			x: this.x - this.ro * 0.866, 
			y: this.y + this.ro * 1.5};
		this.sW = {
			x: this.x - this.ro * 0.866 * 2, 
			y: this.y};
		this.sNW = {
			x: this.x - this.ro * 0.866, 
			y: this.y - this.ro * 1.5};
			
	},
	make: function (x, y, ro) {
	
		this.x = x;
		this.y = y;
		this.ro = ro;
		
		this.path = S.svg("path");
		
		this.position();
		
		// Giving the path a form
		var d = "M " + this.N.x + ", " + this.N.y + " " +
			"L " + this.NE.x + ", " + this.NE.y + " " +
			"L " + this.SE.x + ", " + this.SE.y + " " +
			"L " + this.S.x + ", " + this.S.y + " " +
			"L " + this.SW.x + ", " + this.SW.y + " " +
			"L " + this.NW.x + ", " + this.NW.y + " " +
			"L " + this.N.x + ", " + this.N.y;
			
		this.path.setAttribute("d", d);
		
	},
	addClass: function (className) {
		
		// Check if the class is already defined, or not.
		if (this.path.getAttribute("class")) {
			var classes = this.path.getAttribute("class").split(" ");
			for (var i = 0; i < classes.length; i ++) {
				
				if (classes[i] == className) {
					return;
				}
				
			}
			classes.push(className);
			this.path.setAttribute("class", classes.join(" "));
		} else {
			this.path.setAttribute("class", className);
		}
		
	},
	removeClass: function (className) {
		
		if (this.path.getAttribute("class")) {
			var classes = this.path.getAttribute("class").split(" ");
			var finalClasses = new Array();
			for (var i = 0; i < classes.length; i ++) {
				
				if (classes[i] != className) {
					
					finalClasses.push(classes[i]);
					
				}
				
			}
			
			this.path.setAttribute("class", finalClasses.join(" "));
		}
		
	},
	hasClass: function (className) {
	
		if (this.path.getAttribute("class")) {
			var classes = this.path.getAttribute("class").split(" ");
			for (var i = 0; i < classes.length; i ++) {
				
				if (classes[i] == className) {
				
					return true;
				
				}
				
			}
		}			
	
		return false;
	}
}

S.auxHexa = object(S.baseHexa);
S.auxHexa.draw = function (parent) {
	
	if (!parent) {
		throw Error("Parent hexaGrama was expected");
		return;
	}
	
	this.parent = parent;
	
	this.path.setAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type", "auxHexa");
	
	this.parent.auxLayer.appendChild(this.path);

	this.parent.auxHexas.push(this);
	
}


S.hexa = object(S.baseHexa);
S.hexa.layer = null;
S.hexa.selected = false;
S.hexa.contains = false;
S.hexa.draw = function (parent) {

	if (!parent) {
		throw Error("Parent hexaGrama was expected");
		return;
	}
	
	this.parent = parent;
	
	this.path.setAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type", "hexa");
	this.parent.layer.appendChild(this.path);

	this.parent.hexas.push(this);
	this.path.onclick = function (e) {
	
		if (e.shiftKey) {
		
			S(e.target).select();
		
		} else {
			
			var thisOne = S(e.target);
			thisOne.parent.parent.deselectAll();
			thisOne.select();
		}
	
	}
	
	this.path.ondblclick = function (e) {

		S(e.target).addAuxiliaryHexas();
		
	}
	this.path.oncontextmenu = function (e) {
		
		S(e.target).open();
		return false;
		
	}
	
}

S.hexa.delete = function () {

	// First, delete its path
	this.parent.layer.removeChild(this.path);
	this.path = null;
	
	// Empty the auxiliary Hexas Array
	this.auxiliaryHexas = null;
	
	// TODO: Delete from parent with "getSelfIndex"
	
	// Aufwiedersehen THIS
	delete this;
}

S.hexa.addAuxiliaryHexas = function() {
	
	this.auxiliaryHexas = new Array(); // Refresh the auxHexas buff, and leave them to the garbage collector
	
	this.parent.addAuxHexa(this.sNE.x, this.sNE.y);
	this.parent.addAuxHexa(this.sE.x, this.sE.y);
	this.parent.addAuxHexa(this.sSE.x, this.sSE.y);
	this.parent.addAuxHexa(this.sSW.x, this.sSW.y);
	this.parent.addAuxHexa(this.sW.x, this.sW.y);
	this.parent.addAuxHexa(this.sNW.x, this.sNW.y);
	
}

S.hexa.open = function () {
	
	/* Open, not just your mind
	 * but most your heart and soul
	 * feel this overwhelming wind
	 * of chaos, of passion
	 * and please, don't try to stop it
	 */
	
	// Opening an hexa means, first, check if it has a layer of its own
	if (this.layer) {
		
		// If it has it, is time to make it visible
		this.layer.show();
		
	} else {
		
		// Exciting time! We must build it :)
		this.layer = object(S.hexaLayer);
		this.layer.make();
		this.layer.draw(this.parent.parent, this);
				
		// Now put the signalHexa
		var mySignalHexa = object(S.signalHexa);
		mySignalHexa.make(this.x, this.y, this.ro);
		mySignalHexa.draw(this.layer);
		
	}
	
}
S.hexa.select = function () {

	this.addClass("selected-hexa");
	this.selected = true;
	this.parent.parent.selecteds.push(this);
	
}
S.hexa.deselect = function () {

	this.selected = false;
	this.removeClass("selected-hexa");
	
}

S.signalHexa = object(S.hexa);
delete S.signalHexa.open;
S.signalHexa.draw = function(parent) {

	if (!parent) {
		throw Error("Parent hexaGrama was expected");
		return;
	}
	
	this.parent = parent;
	
	this.path.setAttributeNS("http://www.sumacero.com.ar/2008/hexa", "type", "signalHexa");
	this.addClass("signal-hexa");
	this.parent.layer.appendChild(this.path);

	this.parent.hexas.push(this);
	
	this.parent.signalHexa = this;
	this.path.ondblclick = function (e) {
		
		S(e.target).addAuxiliaryHexas();
	
	}
	
	this.path.oncontextmenu = function (e) {
		
		S(e.target).close();
		return false;
		
	}
	
}

S.signalHexa.close = function () {

	this.parent.hide();
	
}

/////////////////////////////////////////////////
/// ALL THAT STUFF

/* hexaLayer function for check is the space mented to build an hexa es occupied or not. Is it is, it returns the hexa that occupies the place. */
S.hexaLayer.isOccupied = function(xNew, yNew) {
	
	for (var i = 0; i < this.hexas.length; i ++) {
		
		var x = this.hexas[i].x;
		var y = this.hexas[i].y;
		var ro = this.hexas[i].ro;
		
		// Range is that we must allow if is just in the borderline
		var range = 1;
		
		var N = {x: x, y: y - ro * 2 + range};
		var NE = {x: x + ro * 2 * 0.866 - range, y: y - ro + range};
		var SE = {x: x + ro * 2 * 0.866 - range, y: y + ro - range};
		var S = {x: x, y: y + ro * 2 - range};
		var SW = {x: x - ro * 2 * 0.866 + range, y: y + ro - range};
		var NW = {x: x - ro * 2 * 0.866 + range, y: y - ro + range};
		
		/* The first, and most probable thing is that is not at all near the hexagon. 
		 * We check if the rectangle that is defined by the north, the south, east and west is free */
		if (!(xNew < SW.x || xNew > NE.x || yNew < N.y || yNew > S.y)) { // There's a chance that being inside the rectangle, still is outside the hexagon
		
			// North, South or Ecuator??
			if (yNew > N.y && yNew < NW.y) {
			
				// North West, or North East?
				if (xNew < N.x) {
					
					if (0.577 * (xNew - SW.x) > (NW.y - N.y) - (yNew - N.y)) { // This means is inside. Sad
						return this.hexas[i];
					}
					
				} else {

					if (0.577 * ((NE.x - N.x) - (xNew - N.x)) > (NW.y - N.y) - (yNew - N.y)) { // This means is inside. Sad
						return this.hexas[i];
					}

				}
			} else if (yNew > NW.y && yNew < SW.y) {
				return this.hexas[i];
			} else {
				// South West, or South East?
				if (xNew < N.x) {
					
					if (0.577 * (xNew - SW.x) > yNew - SW.y) { // This means is inside. Sad
						return this.hexas[i];
					}
					
				} else {
				
					if (0.577 * ((SE.x - S.x) - (xNew - S.x)) > yNew - SW.y) { // This means is inside. Sad
						return this.hexas[i];
					}
					
				}

			}

						
		}
		
	}
	
	return false;
}

S.hexaGrama.getSelfIndex = function() {
	for (var i = 0; i < S.hexaGramas.length; i ++) {
		if (S.hexaGramas[i] == this) {
			return i;
		}
	}
}

////////////////////////////////////////////////////////////////////
// This testing script

window.onload = function() {
	
	var hexaGrama = object(S.hexaGrama);
	hexaGrama.ro = 30;
	hexaGrama.make();
	hexaGrama.draw(S.el("hexas"));
	hexaGrama.layers[0].addHexa(300, 300);

}
window.onkeypress = function (e) {
	if (e.keyCode == 46) {
		
	}
}
		</script>
	</head>
	<body>
		<div id="hexas">
		</div>
	</body>
</html>